JavaScript中除了基本型別(String/Number/Boolean等),其他型別(Array/Object/Data)實際上都是特定物件延伸而來,這些個特定物件裡面都有自帶的原型,可以稱它為prototype。
當建立一個新的物件時,它的隱藏__proto__
會自動被指到ptototype
,因此這個物件才能夠任意使用prototype
定義好的函式、屬性 => 我們稱之為「原形鏈」。
let arr = new Array()
arr.__proto__ === Array.prototype // true
bind
、call
、apply
三者都是JavaScript Object 的方法
使用 apply
和 call
,可以直接決定並執行一個函數,並告訴它 this 應該是什麼。bind
不會馬上執行函數,而是會給一個新的函數,當這個新的函數被執行時,它會知道 this 應該是先前指定的那個值。
bind
可以綁定一個函數的 this 值,使用 bind 建立一個新的函數時,無論這個新函數在哪裡被呼叫,它的 this 值都會被固定在指定的物件上。
let calculator = {
factor: 2,
multiply: function(number) {
return this.factor * number;
}
};
let double = calculator.multiply;
console.log(double(3)); // 會輸出: NaN,因為 this 現在是全域物件或 undefined
加上bind
來修正 this 指向
let fix = double.bind(calculator);
console.log(fix(3)); // 正確輸出 6
範例程式碼中:
1.先從calculator
中取出multiply
然後賦予值到double
函式
2.在全域呼叫了double
函式,因此this會指向全域,而不是calculator
3.全域中找不到multiply
,因此會回傳全域物件(非嚴格模式)或是 undefined
(嚴格模式)
4.undefined * 3
進行運算會回傳 NAN
(加上bind修正)
5.建立一個新函數fix
,將double
函數的this值綁定到calculator
物件上
6.fix
之後在哪邊呼叫,它的this都會是固定指向calculator
把call
和apply
放在一起講的原因是它們極為相似
最大的不同是 call
接受一連串的參數,而 apply
接受一組陣列形式的參數 --MDN
const restaurant = {
name: "Tasty Restaurant",
bill: function(food, drink) {
console.log(`Bill from ${this.name}:`);
console.log(`Food: ${food}`);
console.log(`Drink: ${drink}`);
}
};
const cafe = {
name: "Cozy Cafe"
};
// 使用 call 來為 cafe 印出bill
restaurant.bill.call(cafe, "Sandwich", "Coffee");
// 輸出:
// Bill from Cozy Cafe:
// Food: Sandwich
// Drink: Coffee
// 使用 apply 來為 cafe 印出bill
restaurant.bill.apply(cafe, ["Croissant", "Latte"]);
// 輸出:
// Bill from Cozy Cafe:
// Food: Croissant
// Drink: Latte
restaurant.bill.call(cafe, "Sandwich", "Coffee")
的作用是調用restaurant
的bill
方法,然後將 this 值指到 cafe
,所以我們只要調用restaurant
方法,輸出的name名稱即會是cafe
基本上apply
跟call
的執行方式是一樣的,相較於call
不同的是,apply
第二個參數是帶入一個Array
以apply做詳細的說明:
1.apply
方法的第一個參數設定指到 this 值的物件,在範例中,我們選擇了 cafe 作為 this 值
2.apply
第二個參數帶入一個Array,這邊帶入「["Croissant", "Latte"]
」做為參數,傳遞給bill
函數
3.當bill
的方法被執行時,他的this值是指向cafe
,這樣this.name
就會輸出"Cozy Cafe"
call
apply
參考文章
JavaScript - call,apply,bind
Function.prototype.bind()
Function.prototype.call